package com.laibatour.generator.code;

import com.laibatour.generator.entity.Table;
import com.laibatour.generator.entity.TableFactory;
import com.laibatour.generator.gen.BaseOutput;
import com.laibatour.generator.gen.MapperJavaOutput;
import com.laibatour.generator.gen.MapperXmlOutput;
import com.laibatour.generator.utils.GeneratorUtil;
import com.laibatour.generator.utils.PropertieUtils;
import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.RuntimeInstance;
import org.apache.velocity.runtime.parser.ParseException;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;


public class GeneratorCode {
    static Logger log = Logger.getLogger(GeneratorCode.class);

    public static void gen(String tablename) {
        //表信息
        List<BaseOutput> outputs = new LinkedList<>();
        Table config = TableFactory.loadConfig(tablename);
        if (config == null || config.getFields().size() == 0) {
            log.error("表不存在或者不存在可用列");
            return;
        }
        outputs.add(new MapperJavaOutput(config));
        outputs.add(new MapperXmlOutput(config));

        //生成代码
        generate(config, outputs);
    }

    private static void generate(Table config, List<BaseOutput> outputs) {

        VelocityEngine ve = new VelocityEngine();
        ve.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
        ve.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
        ve.setProperty(Velocity.RUNTIME_LOG, "");
        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        ve.init();

        VelocityContext ctx = new VelocityContext();
        ctx.put("entity", config);
        ctx.put("LB", GeneratorUtil.class);
        ctx.put("ctx", PropertieUtils.getProp());
        if (outputs == null || outputs.isEmpty()) return;

        for (BaseOutput output : outputs) {
            Template actionTpt = ve.getTemplate(output.getVM());
            String outFile = replaceByCtx(ctx, output.getOutput());
            merge(actionTpt, ctx, outFile);
        }
    }

    private static String replaceByCtx(VelocityContext ctx, String in) {
        StringWriter stringWriter = new StringWriter();

        try {
            RuntimeInstance rs = new RuntimeInstance();
            Template template = new Template();
            template.setRuntimeServices(rs);
            template.setData(rs.parse(in, "template_name"));
            template.initDocument();
            template.merge(ctx, stringWriter);
            return stringWriter.toString();
        } catch (ParseException e) {
            log.error("replaceByCtx", e);
            return in;
        }
    }

    private static void merge(Template template, VelocityContext ctx, String output) {
        try (FileOutputStream ios = new FileOutputStream(output);
             OutputStreamWriter osWriter = new OutputStreamWriter(ios, StandardCharsets.UTF_8);
             PrintWriter writer = new PrintWriter(osWriter)) {
            template.merge(ctx, writer);
            writer.flush();
        } catch (Exception e) {
            log.error("GeneratorCode", e);
        }
    }

}
